package com.baicaoyuan.web.service;

import com.baicaoyuan.web.common.LogUtil;
import com.baicaoyuan.web.common.PlatformIdConfig;
import com.baicaoyuan.web.common.relation.RelationCache;
import com.baicaoyuan.web.model.*;
import com.baicaoyuan.web.repository.*;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.hash.Hashing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class JzzFlowService {

    @Autowired
    JzzProfitInputRepository jzzProfitInputRepository;

    @Autowired
    JzzCurveRepository jzzCurveRepository;

    @Autowired
    JzzUserRepository jzzUserRepository;
    @Autowired
    RelationCache relationCache;

    @Autowired
    UserRepository userRepository;
    @Autowired
    JzzUserProjectRepository jzzUserProjectRepository;

    @Autowired
    JzzProfitFlowRepository jzzProfitFlowRepository;

    @Autowired
    PlatformIdConfig platformIdConfig;

    //    @Scheduled(cron = "0 1 0 * * ?")
    @Scheduled(cron = "0 0/5 * * * ?")
    public void flow() {
//        String yesterday = yesterday();
//        String begin = yesterday + " 00:00:00";
//        String end = yesterday + " 23:59:59";
        List<JzzProfitInputDO> list = jzzProfitInputRepository.queryJzzProfitInput(1);
        shareProfit(list);
    }

    public boolean modifySon(String oldSno, String newSno) throws Exception {
        Integer integer = jzzProfitFlowRepository.countBySerialNumber(oldSno);
        if (integer > 0) {
            throw new Exception("已分润，无法修改！");
        }
        return jzzUserProjectRepository.updateSno(newSno, oldSno) > 0;
    }

    /**
     * 分润 当前时间的前一天
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    void shareProfit(List<JzzProfitInputDO> list) {
        if (!CollectionUtils.isEmpty(list)) {
            JzzCurveDO curve = jzzCurveRepository.findTopOrderByIdDesc();
            list.forEach(x -> {
                shareOneProfitInput(x, curve);
            });

            sharePlatform(list, curve);
        }
    }

    private String yesterday() {
        String yesterday = LocalDate.now().plusDays(-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return yesterday;
    }

    //平台30%推送金种子上涨
    private void sharePlatform(List<JzzProfitInputDO> list, JzzCurveDO curve) {
        if (!CollectionUtils.isEmpty(list)) {
            BigDecimal sum = BigDecimal.ZERO;
            for (JzzProfitInputDO x : list) {
                sum = sum.add(x.getPercentGrowProfit());
            }

            JzzCurveDO newCurve = new JzzCurveDO();
            newCurve.setTotalPrice30(sum);
            newCurve.setJzzBaseNumber(new BigDecimal(platformIdConfig.getCirculation()));

            BigDecimal nowTotalPrice = curve.getTotalPrice().add(sum);
            newCurve.setTotalPrice(nowTotalPrice);
            BigDecimal price = nowTotalPrice.divide(newCurve.getJzzBaseNumber(), 8, BigDecimal.ROUND_HALF_UP);
            newCurve.setPrice(price);

            List<String> periodNos = list.stream().map(JzzProfitInputDO::getPeriodNo).distinct().collect(Collectors.toList());
            newCurve.setSumPeriodNo(Joiner.on(",").join(periodNos));
            jzzCurveRepository.save(newCurve);
        }
    }

    /**
     * 一条利润的记录
     *
     * @param profitInput
     */
    private void shareOneProfitInput(JzzProfitInputDO profitInput, JzzCurveDO curve) {
        Objects.requireNonNull(profitInput);

        JzzUserProjectDO userProject = jzzUserProjectRepository.findBySerialNumberAndStatus(profitInput.getSerialNumber(), "1");

        if (userProject != null) {
            UserDO userDO = userRepository.findOne(userProject.getUserId());

            //本人自己参与挖矿
            Long myselfId = userProject.getUserId();
            if (checkJzzUser(myselfId)) {
                BigDecimal myselfJzzNumber = computeJzzNumber(profitInput.getPercentMyselfProfit(), curve.getPrice());
                JzzProfitFlowDO myself = new JzzProfitFlowDO(
                        null,
                        profitInput.getPeriodNo(),
                        profitInput.getSerialNumber(),
                        myselfId,
                        0,
                        profitInput.getId(),
                        userProject.getProjectId(),
                        profitInput.getPercentMyselfProfit(),
                        curve.getPrice(),
                        myselfJzzNumber, "", null);

                String md = md5(myself);
                myself.setMd5(md);

                jzzProfitFlowRepository.save(myself);
                jzzUserRepository.updateJzzNumberDig(myselfId, myselfJzzNumber);
            }

            if (userDO.getUserDirectId() != null && checkJzzUser(userDO.getUserDirectId())) {
                BigDecimal directJzzNumber = computeJzzNumber(profitInput.getPercentDirectProfit(), curve.getPrice());
                JzzProfitFlowDO direct = new JzzProfitFlowDO(
                        null,
                        profitInput.getPeriodNo(),
                        profitInput.getSerialNumber(),
                        userDO.getUserDirectId(),
                        1,
                        profitInput.getId(),
                        userProject.getProjectId(),
                        profitInput.getPercentDirectProfit(),
                        curve.getPrice(),
                        directJzzNumber, "", null);


                String md = md5(direct);
                direct.setMd5(md);

                jzzProfitFlowRepository.save(direct);
                jzzUserRepository.updateJzzNumberDig(userDO.getUserDirectId(), directJzzNumber);
            }

            if (userDO.getUserIndirectId() != null && checkJzzUser(userDO.getUserIndirectId())) {
                BigDecimal indirectJzzNumber = computeJzzNumber(profitInput.getPercentIndirectProfit(), curve.getPrice());
                JzzProfitFlowDO indirect = new JzzProfitFlowDO(
                        null,
                        profitInput.getPeriodNo(),
                        profitInput.getSerialNumber(),
                        userDO.getUserIndirectId(),
                        2,
                        profitInput.getId(),
                        userProject.getProjectId(),
                        profitInput.getPercentIndirectProfit(),
                        curve.getPrice(),
                        indirectJzzNumber, "", null);
                String md = md5(indirect);
                indirect.setMd5(md);
                jzzProfitFlowRepository.save(indirect);
                jzzUserRepository.updateJzzNumberDig(userDO.getUserIndirectId(), indirectJzzNumber);
            }

            List<Long> teamLeaders = checkJzzUser(relationCache.getTeamLeader());
            if (!CollectionUtils.isEmpty(teamLeaders)) {
                BigDecimal oneTeamLeaderProfit = profitInput.getPercentTeamLeaderProfit().divide(new BigDecimal(teamLeaders.size()));
                BigDecimal OneTeamLeaderJzzNumber = computeJzzNumber(oneTeamLeaderProfit, curve.getPrice());
                teamLeaders.forEach(teamLeaderId -> {

                            JzzProfitFlowDO tl = new JzzProfitFlowDO(
                                    null,
                                    profitInput.getPeriodNo(),
                                    profitInput.getSerialNumber(),
                                    teamLeaderId,
                                    3,
                                    profitInput.getId(),
                                    userProject.getProjectId(),
                                    oneTeamLeaderProfit,
                                    curve.getPrice(),
                                    OneTeamLeaderJzzNumber, "", null);
                            String md = md5(tl);
                            tl.setMd5(md);
                            jzzProfitFlowRepository.save(tl);
                            jzzUserRepository.updateJzzNumberDig(teamLeaderId, OneTeamLeaderJzzNumber);
                        }

                );
            }
        } else {
            LogUtil.Info(String.format("利润数据不合法！periodNo:%s serialNumber :%s", profitInput.getPeriodNo(), profitInput.getSerialNumber()));
        }


        //分润结束标识
        jzzProfitInputRepository.updateStatus(profitInput.getId(), 2);
    }


    /**
     * 挖金种子 利润 /金种子单价
     *
     * @param profit
     * @param price
     * @return
     */
    private BigDecimal computeJzzNumber(BigDecimal profit, BigDecimal price) {

        return profit.divide(price, 8, BigDecimal.ROUND_HALF_UP);
    }

    private boolean checkJzzUser(Long userId) {
        JzzUserDO user = jzzUserRepository.findByUserId(userId);
        return user != null && "1".equals(user.getStatus());
    }

    private List<Long> checkJzzUser(List<Long> teamLeaders) {
        if (teamLeaders == null) return null;
        return teamLeaders.stream().filter(x ->
                checkJzzUser(x)
        ).collect(Collectors.toList());
    }

    private String md5(JzzProfitFlowDO inputFlow) {
        String source = mdSource(inputFlow) + "";
        return Hashing.md5().newHasher().putString(source, Charsets.UTF_8).hash().toString();
    }

    private String mdSource(JzzProfitFlowDO inputFlow) {
        Map<String, Object> map = new HashMap<>();
        map.put("periodNo", inputFlow.getPeriodNo());
        map.put("serialNumber", inputFlow.getSerialNumber());
        map.put("userId", inputFlow.getUserId());
        map.put("userType", inputFlow.getUserType());
        map.put("jzzProfitInputId", inputFlow.getJzzProfitInputId());
        map.put("jzzUserProjectId", inputFlow.getJzzUserProjectId());
        map.put("profit", inputFlow.getProfit());
        map.put("jzzPrice", inputFlow.getJzzPrice());
        map.put("jzzNumber", inputFlow.getJzzNumber());
        List<String> tempList = new ArrayList<>(map.keySet());
        String sourceSign = "";
        Collections.sort(tempList, String.CASE_INSENSITIVE_ORDER);//排序
        for (String key : tempList) {
            sourceSign += key + map.get(key);//拼接原始sign
        }
        return sourceSign;
    }
}
